#include "P2PChat.h"

/**
 * Init the null instance for the singletone controller
 */
P2PChat* P2PChat::instance = NULL;

P2PChat::P2PChat()
{
	isConnected = false;
	as = new AliveSender();
	ac = new AliveConsumer();
	//se = Qrm3Controller::getInstance()->getSettingsExpert();
	msgConsumer = new MessagesConsumer();
	users = new QMap<QString, User *>;
	usersMutex = new QMutex();
	connectionTimer = new QTimer();
	connectionTimer->setInterval(1000);	//1 per second
	connectionWarmup = 40;		//wait 40 seconds to grab other users
	commands = new QMap<QByteArray, Command *>;
	mySelf = new User(
			QByteArray("new#"),
			QString("127.0.0.1"),	//just a fake (not used)
			QByteArray(""),
			true);
	connect(connectionTimer,	SIGNAL(timeout()),					this, SLOT(warmupTimeout()));
	connect(as,					SIGNAL(userDisconnected(User *)),	this, SLOT(processUserDisconnected(User *)));
	initCommands();
}

/**
 * Singletone get instance
 */
P2PChat* P2PChat::getInstance()
{
	if(instance == NULL)
	{
		instance = new P2PChat();
	}
	
	return instance;
}

/**
 * setter and getters functions
 */
void P2PChat::setMySelf(User *u)
{
	mySelf = u;
}

void P2PChat::initCommands()
{
	Command *ac = new AliveCommand();
	
	commands->insert(ac->getTag(), ac);
}

QMap<QByteArray, Command *> * P2PChat::getCommands()
{
	return commands;
}

User* P2PChat::getMySelf()
{
	return mySelf;
}

QMap<QString, User *> * P2PChat::getUsers()
{
	return users;
}

QMutex* P2PChat::getUserMutex() { return usersMutex; }

/**
 * SLOT:
 * Start all threads that hear messages (Alive, Msg, etc...) from other users
 */
void P2PChat::startChat()
{
	if(!isConnected)
	{
		/* refresh myself data */
		mySelf->setNick(
			Qrm3Controller::getInstance()->getSettingsExpert()->getSetting(SETTINGS_CHAT_NICKNAME).toString());
		mySelf->setRealName(
					Qrm3Controller::getInstance()->getSettingsExpert()->getSetting(SETTINGS_CHAT_REALNAME).toString());
		
		Qrm3Controller::getInstance()->getGui()->ui.warmupLabel->setText("Wait...acquiring connected users");
		
		/* Change the button connect to disconnect */
		Qrm3Controller::getInstance()->getGui()->ui.disconnectConnectButton->setText("Disconnect");
				
		
		/* Start threads */
		ac->start();
		as->getTimer()->start();
		msgConsumer->start();
		connectionTimer->start();
		isConnected = true;
	}
	else
	{
		//disconnect!
		stopChat();
	}
}


/**
 * SLOT:
 * Stop all threads that hear messages (Alive, Msg, etc...) from other users
 */
void P2PChat::stopChat()
{
	/* reset lcd and label warmup */
	Qrm3Controller::getInstance()->getGui()->ui.warmupLabel->setText("");
	Qrm3Controller::getInstance()->getGui()->ui.warmupLcd->display(0);
	
	/* Stop services */
	ac->quit();
	as->getTimer()->stop();
	msgConsumer->quit();
	connectionTimer->stop();
	isConnected = false;
	
	/* Clear user list */
	Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->clear();
	
	/* Change the button disconnect to connect */
	Qrm3Controller::getInstance()->getGui()->ui.disconnectConnectButton->setText("Connect");
	
	/* Lock chat */
	Qrm3Controller::getInstance()->lockChat();
	
	/* Clear and free the users map */
	QListIterator<QString> keysIterator(users->keys());
	while(keysIterator.hasNext())
	{
		//delete from map
		User *u = users->take(keysIterator.next());
		
		//free
		delete u;
	}
	
}


/**
 * Set the state of the chat (connected or disconnected)
 * @param bool state
 */
void P2PChat::setConnected(bool state)
{
	isConnected = state;
}

/**
 * SLOT:
 * Save inside Settings the identity
 */
void P2PChat::saveIdentity()
{
	QString nickName(Qrm3Controller::getInstance()->getUserIdentityGui()->ui.nickName->text());
	QString realName(Qrm3Controller::getInstance()->getUserIdentityGui()->ui.realName->text());
	
	/* Replace '<' and '>' */
	nickName = nickName.replace("<", "");
	nickName = nickName.replace(">", "");
	
	realName = realName.replace("<", "");
	realName = realName.replace(">", "");
	
	if(nickName.trimmed() == "")
	{	
		Qrm3Controller::getInstance()->getUserIdentityGui()->ui.nickName->setText(
				Qrm3Controller::getInstance()->getSettingsExpert()->getSetting(SETTINGS_CHAT_NICKNAME).toString());
		Qrm3Controller::getInstance()->getUserIdentityGui()->ui.realName->setText(
				Qrm3Controller::getInstance()->getSettingsExpert()->getSetting(SETTINGS_CHAT_REALNAME).toString());
		return;
	}
	
	/* Store settings */
	Qrm3Controller::getInstance()->getSettingsExpert()->registerQByteArraySetting(SETTINGS_CHAT_NICKNAME, nickName.toUtf8());
	Qrm3Controller::getInstance()->getSettingsExpert()->registerQByteArraySetting(SETTINGS_CHAT_REALNAME, realName.toUtf8());
	Qrm3Controller::getInstance()->getSettingsExpert()->forceSync();
	
	/* Refresh values */
	Qrm3Controller::getInstance()->getUserIdentityGui()->ui.nickName->setText(
			Qrm3Controller::getInstance()->getSettingsExpert()->getSetting(SETTINGS_CHAT_NICKNAME).toString());
	Qrm3Controller::getInstance()->getUserIdentityGui()->ui.realName->setText(
			Qrm3Controller::getInstance()->getSettingsExpert()->getSetting(SETTINGS_CHAT_REALNAME).toString());
		
	
	/* Refresh label nick */
	Qrm3Controller::getInstance()->getGui()->ui.nickNameLabel->setText(
			Qrm3Controller::getInstance()->getSettingsExpert()->getSetting(SETTINGS_CHAT_NICKNAME).toString());

	
	/* refresh the value inside myself User instance */
	QMutexLocker locker(usersMutex); //LOCK
	mySelf->setNick(nickName);
	mySelf->setRealName(realName);
}

/**
 * Slot:
 * show to the user the time count down, before start the chat
 * (users acquiring)
 */
void P2PChat::warmupTimeout()
{
	
	if(connectionWarmup == 0)
	{
		connectionTimer->stop();
		connectionWarmup = 40; //restore
		
		usersMutex->lock();	//LOCK
		
		Qrm3Controller::getInstance()->getGui()->ui.chatTextArea->setText(
				"--> " + *(mySelf->getNick()) + " has joined.");
		
		Qrm3Controller::getInstance()->getGui()->ui.warmupLabel->setText("Connected users");
		
		Qrm3Controller::getInstance()->getGui()->ui.warmupLcd->display(users->size() + 1);
		usersMutex->unlock();
		
		/* Add users founded inside the list */
		addKnownUsers();
		
		/* unlock the chat */
		Qrm3Controller::getInstance()->unlockChat();
		
		return;
	}
	Qrm3Controller::getInstance()->getGui()->ui.warmupLcd->display(connectionWarmup);
	
	
	connectionWarmup--;
}

/**
 * Add this user inside the gui, and show it as [connected]...
 */
void P2PChat::addConnectedUser(User *s)
{
	if(connectionWarmup == 40)
	{
		Qrm3Controller::getInstance()->getGui()->ui.chatTextArea->append(
			"--> " + *(s->getNick()) + " has joined." + " (" + s->getAddress()->toString() + ")");
		
		/* Add the user into the list */
		QListWidgetItem *item = new QListWidgetItem(QIcon(":/qrm3wifi_user_unlocked"), *(s->getNick()));
		item->setData(Qt::ToolTipRole, "<b>Real Name:</b> " + *(s->getRealName()) + "<br /><b>IP-Address:</b> " + s->getAddress()->toString());
		item->setData(Qt::UserRole, *(s->getID()));
		
		Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->addItem(item);
		
		//allready locked by the caller (AliveCommand)
		Qrm3Controller::getInstance()->getGui()->ui.warmupLcd->display(users->size() + 1);
		
		//sort
		Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->sortItems();
	}
}

void P2PChat::addKnownUsers()
{
	QMutexLocker lock(usersMutex);
	
	QMapIterator<QString, User*> it(*users);
	while(it.hasNext())
	{
		it.next();
		QListWidgetItem *item = new QListWidgetItem(QIcon(":/qrm3wifi_user_unlocked"), *(it.value()->getNick()));
		item->setData(Qt::ToolTipRole, "<b>Real Name:</b> " + *(it.value()->getRealName()) + "<br /><b>IP-Address:</b> " + it.value()->getAddress()->toString());
		item->setData(Qt::UserRole, *(it.value()->getID()));
		Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->addItem(item);
	}
	
	/* Insert myself and magify it with red foreground */
	QListWidgetItem *myselfItem = new QListWidgetItem(QIcon(":/qrm3wifi_user_unlocked"), *(mySelf->getNick()));
	myselfItem->setData(Qt::ToolTipRole,  "<b>YOURSELF<b>");
	myselfItem->setData(Qt::UserRole, *(mySelf->getID()));
	myselfItem->setForeground(QColor(Qt::red));
	Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->addItem(myselfItem);
	
	//sort
	Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->sortItems();
	
}

void P2PChat::processUserDisconnected(User *s)
{

	/* Search for nick, and select the correct by the ID */
	QList<QListWidgetItem *> us = Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->findItems(*(s->getNick()) ,Qt::MatchCaseSensitive);
	QListIterator<QListWidgetItem *> i(us);
	
	while(i.hasNext())
	{
		QListWidgetItem *current = i.next();
		
		QByteArray currentID = current->data(Qt::UserRole).toByteArray();
		qDebug() << "id:" << currentID;
		if(currentID == *(s->getID()))
		{
			//delete it!
			Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->takeItem(
					Qrm3Controller::getInstance()->getGui()->ui.usersListWidget->row(current)); 
			
			qDebug() << "deleted!";
			break;
		}
		
	}
	
	/* Notify to text area */
	Qrm3Controller::getInstance()->getGui()->ui.chatTextArea->append(
				"<-- " + *(s->getNick()) + " has left." + " (" + s->getAddress()->toString() + ")");
	
	//refresh count (allready locked by caller)
	Qrm3Controller::getInstance()->getGui()->ui.warmupLcd->display(users->size() + 1);
}
